

// infer 推导类型   通常与extends配合使用出现在三种地方
// 1 出现在extends条件语句后的函数类型的参数类型位置上
// 2 出现在extends条件语句后的函数类型的返回值类型位置上
// 3 出现在类型的泛型额具体化类型上

type fn = (param: number) => string
type fn2 = (param: number, param2: string) => string
type InferType<T> = T extends (param: infer P) => unknown ? P : T
// 在类型InferType中会判断传入的类型是不是接受一个属性，返回一个值得函数，如果成立则返回这个函数属性的类型，否则返回传入的T类型
// 传入fn：因为与定义的(param: infer P) => unknown类型匹配，则p代表推导出的fn参数的类型，进行返回则得到number类型
// 传入fn2：因为fn2需要的参数比InferType中需要的参数更多则约束不成立，得到传入的fn2类型（在extends中 函数的情况下 如果前置的函数类型参数比后置的函数类型参数少，其他条件相同的情况下成立）

type InferTypeTwo<T> = T extends (param: number) => infer P ? P : T
// 传入fn：类型匹配成立，则p代表推导出的fn的返回值的类型，进行返回则得到string类型
// 传入fn2：类型匹配不成立，得到传入的fn2类型

// type fn = (param: number) => string
type InferTypeDist = InferType<fn>
type InferTypeDist2 = InferType<fn2>

type InferTypeTwoDist = InferTypeTwo<fn>
type InferTypeTwoDist2 = InferTypeTwo<fn2>

type ConstructorParamsType<T> = T extends new (...arg: infer P) => unknown ? P : never;

const asdfM = <T extends new (...arg: unknown[]) => unknown, K extends new (...arg: unknown[]) => unknown>(constructor: T, ...args: ConstructorParamsType<K>) => { }

type Extracts<T, U> = T extends U ? T : never;
type Type1 = Extracts<{username: string}, object>
type Type11 = Extracts<{username: string, username2: string}, {username: string, username2: string, username3: string}>

type Type2 = Extracts<string, object>
type Type3 = Extracts<"string" | "number" | "name" | "age", "number" | "string" | "boolean" | "name">
type Type5 = Extracts<number | "name" | "age", number | string | boolean>


type Excludes<T, U> = T extends U ? never : T;
type Type4 = Excludes<"string" | "number" | "name" | "age", "number" | "string" | "boolean">
type Type6 = Excludes<"string" | "number" | "name" | "age", string>


type OneType<T> = T extends keyof any ? T : never;
// keyof any === type OneType = string | number | symbol

type OneResultType = OneType<boolean>

type PortionPartial<T, K extends keyof T> = Omit<T, K> & {
    [P in K]?: T[P]
};

interface Aa {
    name: string;
    age: string;
    six: string
}

type typeTwo = PortionPartial<Aa, "name" | "age">

const aa: typeTwo = {
    six: "",
    // age: ""
}

type ASD<T, K> = Exclude<keyof T, K>

type ASF = ASD<{a: string, c: string, b: string}, "a" | "b">

// type aaAa = Aa & {name: string}
// const testAaAa: aaAa = {
//     age: "",
//     six: ""
// }

type RequiredPartial<T, K extends keyof T> = Omit<T, K> & {
    [P in K]-?: T[P]
};
interface Bb {
    name?: string;
    age?: string;
    six?: string
}

type OmitTest = Omit<Bb, "name">
type typeThree = RequiredPartial<Bb, "name" | "age">

const bb: typeThree = {
    age: "",
    name: ""
}

type fn1 = (a: string, b: number) => string;
type fn3 = (a: string) => string;

type FnType1 = fn1 extends fn3 ? fn1 : never
type FnType2 = fn3 extends fn1 ? fn3 : never


const people = {
    name: "张三",
    age: 33
}

type People = typeof people;
type KeyofType = keyof People;

type Requireds<T> = {
    [P in keyof T]: T[P];
};

type TestA = Readonly<{name: string}>

const testA: TestA = {
    name: "name",
}
testA.name = "asdf"

const testB = {
    name: "name"
} as const;

testB.name = "name2"


type CreateInterfaceType<K extends keyof any, T> = {
    [P in K]: T;
};

type ObjType = CreateInterfaceType<"name" | "age", boolean>;
